<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>截图粘贴OCR</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #333;
            line-height: 1.6;
            min-height: 100vh;
            padding: 10px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        header {
            text-align: center;
            margin-bottom: 10px;
            color: white;
            padding: 10px;
        }

        h1 {
            font-size: 2.8rem;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }

        .description {
            font-size: 1.2rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
        }

        .content-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 30px;
            margin-bottom: 10px;
        }

        .card {
            background: white;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            display: flex;
            flex-direction: column;
            height: 100%;
        }

        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
        }

        .card-header {
            padding: 25px;
            color: white;
            font-size: 1.6rem;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 12px;
        }

        .image-card .card-header {
            background: linear-gradient(to right, #FF416C, #FF4B2B);
        }

        .list-card .card-header {
            background: linear-gradient(to right, #3494E6, #EC6EAD);
        }

        .json-card .card-header {
            background: linear-gradient(to right, #00cdac, #02aab0);
        }

        .card-content {
            padding: 25px;
            flex: 1;
            display: flex;
            flex-direction: column;
            max-height: 550px;
            overflow: auto;
        }

        /* 图片卡片样式 */
        .image-container {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            border-radius: 10px;
            background: #f8f9fa;
        }

        .image-container img {
            width: 100%;
            height: 280px;
            object-fit: cover;
            transition: transform 0.5s ease;
        }

        .image-container:hover img {
            transform: scale(1.05);
        }

        .image-info {
            margin-top: 20px;
            text-align: center;
            color: #666;
        }

        /* 列表卡片样式 */
        .list-container {
            flex: 1;
        }

        .feature-list {
            list-style: none;
        }

        .feature-list li {
            padding: 15px 0;
            border-bottom: 1px solid #eee;
            display: flex;
            align-items: center;
            gap: 15px;
            transition: background-color 0.2s ease;
        }

        .feature-list li:hover {
            background-color: #f9f9f9;
        }

        .feature-list li:last-child {
            border-bottom: none;
        }

        .feature-list i {
            font-size: 1.3rem;
            width: 30px;
            height: 30px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            color: white;
        }

        .feature-list li:nth-child(1) i {
            background: #FF416C;
        }

        .feature-list li:nth-child(2) i {
            background: #3494E6;
        }

        .feature-list li:nth-child(3) i {
            background: #00cdac;
        }

        .feature-list li:nth-child(4) i {
            background: #FF4B2B;
        }

        .feature-list li:nth-child(5) i {
            background: #EC6EAD;
        }

        /* JSON卡片样式 */
        .json-container {
            flex: 1;
            background: #2d3748;
            color: #e2e8f0;
            border-radius: 10px;
            padding: 10px;
            overflow: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.95rem;
            line-height: 1.5;
        }

        .json-key {
            color: #63b3ed;
        }

        .json-string {
            color: #68d391;
        }

        .json-number {
            color: #f6ad55;
        }

        .json-boolean {
            color: #fc8181;
        }

        .json-null {
            color: #a0aec0;
        }

        .json-indent {
            padding-left: 20px;
        }

        footer {
            text-align: center;
            color: white;
            padding: 20px;
            margin-top: 40px;
            opacity: 0.9;
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .content-grid {
                grid-template-columns: 1fr;
            }

            h1 {
                font-size: 2.2rem;
            }

            .card-header {
                font-size: 1.4rem;
            }
        }

        @media (max-width: 480px) {
            h1 {
                font-size: 1.8rem;
            }

            .card-header {
                padding: 20px;
                font-size: 1.3rem;
            }

            .card-content {
                padding: 20px;
            }
        }

        /* 模态框样式 */
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.9);
            animation: fadeIn 0.3s;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
            }

            to {
                opacity: 1;
            }
        }

        .modal-content {
            display: block;
            margin: 50px auto;
            max-width: 90%;
            max-height: 80%;
            border-radius: 4px;
            animation: zoom 0.3s;
        }

        @keyframes zoom {
            from {
                transform: scale(0.9);
            }

            to {
                transform: scale(1);
            }
        }

        #caption {
            margin: 15px auto;
            text-align: center;
            color: #ccc;
            font-size: 1.1rem;
        }

        .close {
            position: absolute;
            top: 15px;
            right: 35px;
            color: #f1f1f1;
            font-size: 40px;
            font-weight: bold;
            cursor: pointer;
            transition: 0.3s;
        }

        .close:hover {
            color: #bbb;
        }

        .image-preview {
            display: none;
            margin-top: 30px;
            text-align: center;
        }

        .image-preview img {
            max-width: 100%;
            max-height: 400px;
            border-radius: 8px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            border: 1px solid #ddd;
        }

        .button {
            background: #3498db;
            color: white;
            border: none;
            padding: 6px 12px;
            border-radius: 6px;
            font-size: 16px;
            cursor: pointer;
            transition: background 0.3s;
            margin: 10px 5px;
            display: inline-block;
        }

        .button:hover {
            background: #2980b9;
        }

        .button-secondary {
            background: #2ecc71;
        }

        .button-secondary:hover {
            background: #27ae60;
        }

        .key-shortcut {
            display: inline-block;
            background: #eef2f7;
            padding: 2px 3px;
            border-radius: 4px;
            font-weight: bold;
            color: #2c3e50;
            margin: 0 5px;
        }
    </style>
</head>

<body>
    <div class="container">
        <header>
            <h1>截图粘贴OCR</h1>
            <p class="description">尝试使用快捷键截图后，在此页面粘贴（Ctrl+V），或直接将图片文件拖放到下方区域</p>
        </header>

        <div class="content-grid">
            <!-- 图片卡片 -->
            <div id="pasteArea" class="card image-card">
                <div class="card-header">
                    <i class="fas fa-paste"></i>
                    <span>粘贴拖放</span>
                </div>
                <div class="card-content">
                    <div class="image-container">
                        <img id="expandable-image" src="https://images.unsplash.com/photo-1506744038136-46273834b3fb"
                            alt="预览图片">
                    </div>
                    <!--div class="image-info">
                        <p>美丽的山脉风景 - 拍摄于加拿大班夫国家公园</p>
                    </div-->
                    <div class="image-preview" id="imagePreview">
                        <div class="actions">
                            <button id="downloadORCData" class="button">下载数据</button>
                            <button id="recognizeText" class="button">PaddleOCR</button>
                            <button id="handerOllama" class="button">Ollama</button>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 列表卡片 -->
            <div id="copyButton" title="点击复制data" class="card list-card">
                <div class="card-header">
                    <i class="fas fa-list"></i>
                    <span>PaddleOCR</span>
                </div>
                <div class="card-content">
                    <div class="list-container">
                        <ul id="text-recognition" class="feature-list">
                            <li>
                                <i class="fas fa-check"></i>
                                <div>
                                    <h3>如何截图并粘贴</h3>
                                    <p>使用截图工具截取屏幕（全屏、区域或应用窗口）</p>
                                </div>
                            </li>
                            <li>
                                <i class="fas fa-bolt"></i>
                                <div>
                                    <h3>Windows</h3>
                                    <p>按 <span class="key-shortcut">PrtScn</span> 或 <span
                                            class="key-shortcut">Win+Shift+S</span></p>
                                </div>
                            </li>
                            <li>
                                <i class="fas fa-lock"></i>
                                <div>
                                    <h3>Mac</h3>
                                    <p>按 <span class="key-shortcut">Cmd+Shift+4</span></p>
                                </div>
                            </li>
                            <li>
                                <i class="fas fa-sync"></i>
                                <div>
                                    <h3>截图后</h3>
                                    <p>点击此页面并按 <span class="key-shortcut">Ctrl+V</span> (Windows) 或 <span
                                            class="key-shortcut">Cmd+V</span>
                                        (Mac)</p>
                                </div>
                            </li>
                            <li>
                                <i class="fas fa-users"></i>
                                <div>
                                    <h3>其他</h3>
                                    <p>或者直接将图片文件拖放到上方区域</p>
                                </div>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>

            <!-- JSON卡片 -->
            <div class="card json-card">
                <div class="card-header">
                    <i class="fas fa-code"></i>
                    <span>Ollama</span>
                </div>
                <div class="card-content">
                    <textarea id="ollamaResult" class="json-container"></textarea>
                </div>
            </div>
        </div>

        <!-- 图片放大模态框 -->
        <div id="image-modal" class="modal">
            <span class="close">&times;</span>
            <img class="modal-content" id="modal-image">
            <div id="caption"></div>
        </div>


        <footer>
            <p>© 2023 多内容类型展示页面 | 设计精美，体验卓越</p>
        </footer>
    </div>

    <script>
        // 获取模态框元素
        var modal = document.getElementById("image-modal");

        // 获取图片和模态框图片元素
        var img = document.getElementById("expandable-image");
        var modalImg = document.getElementById("modal-image");
        var captionText = document.getElementById("caption");

        // 点击图片打开模态框
        img.onclick = function () {
            modal.style.display = "block";
            modalImg.src = this.src;
            captionText.innerHTML = this.alt;
        }

        // 获取关闭按钮
        var span = document.getElementsByClassName("close")[0];

        // 点击关闭按钮关闭模态框
        span.onclick = function () {
            modal.style.display = "none";
        }

        // 点击模态框背景关闭
        modal.onclick = function (event) {
            if (event.target == modal) {
                modal.style.display = "none";
            }
        }

        // 按ESC键关闭模态框
        document.addEventListener('keydown', function (event) {
            if (event.key === "Escape") {
                modal.style.display = "none";
            }
        });
    </script>

    <script>

        function scrollToBottom() {
            const ollamaResult = document.getElementById('ollamaResult');
            ollamaResult.scrollTop = ollamaResult.scrollHeight;
        }

        let ocrData = {};

        class OllamaApiChat {
            constructor() {
                this.init();
            }
            init() {
                this.url = "http://192.168.2.102:11434";
                this.url_api_chat = this.url + "/api/chat";
                this.url_api_tags = this.url + "/api/tags";
                this.think = "";
                this.model_name = "qwen3:1.7b";
                this.models = {};
                this.fetchTags();
                this.messages = [{ role: "system", content: "请根据用户输入的内容，整理出题目、选项、答案和解释，使用json格式输出。格式示例：\n{'题目':'','选项':[{'选项':'A','内容':''},{'选项':'B','内容':''},{'选项':'C','内容':''},{'选项':'D','内容':''}],'正确答案':'','解析':''}" }];
                this.stream = true;
                this.options = { temperature: 0.5, seed: 42 };
            }
            async fetchTags(url) {
                try {
                    const response = await fetch(this.url_api_tags);
                    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
                    const data = await response.json();
                    const models = {};
                    data.models.forEach(model => this.models[model.name] = `${Math.floor(model.size / 1024 / 1024)} MB`);
                    const ollamaResult = document.getElementById('ollamaResult');       // 粘贴/拖放区域
                    ollamaResult.value = JSON.stringify(this.models, null, 2);
                    //console.log(this.models);
                } catch (error) {
                    console.error('Error fetching data:', error);
                }
            }
            async streamChat(text) {
                const ollamaResult = document.getElementById('ollamaResult');       // 粘贴/拖放区域
                ollamaResult.value = "<-- Ollama 启动 -->\n";
                this.messages.push({ role: "user", content: text });
                const payload = {
                    model: this.model_name,
                    messages: [...this.messages],
                    stream: this.stream,
                    options: { ...this.options }
                };
                const response = await fetch(this.url_api_chat, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Accept": "text/event-stream"
                    },
                    body: JSON.stringify(payload)
                });
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let buffer = "";
                let messages = "";
                while (true) {
                    const { done, value } = await reader.read();
                    if (done) break;
                    buffer += decoder.decode(value, { stream: true });
                    const chunks = buffer.split("\n");
                    buffer = chunks.pop();
                    for (const chunk of chunks) {
                        if (chunk.trim() === "") continue;
                        try {
                            const data = JSON.parse(chunk);
                            messages += data.message.content;
                            ollamaResult.value += data.message.content;
                            scrollToBottom()
                        } catch (e) {
                            console.error("Failed to parse chunk:", chunk);
                        }
                    }
                }
                const [think, content] = messages.trim().split(/(<think>|<\/think>)/).filter(part => {
                    return part !== '' && part !== "<think>" && part !== "</think>";
                });
                this.think = think.trim();
                this.messages.push({ role: "assistant", content: content.trim() });
                ollamaResult.value += "\n\n<-- Ollama 完成 -->";
                scrollToBottom();
                ocrData = { ...this.messages };
            }
        }
        const OAC = new OllamaApiChat();

        // 当DOM内容加载完成后执行
        document.addEventListener('DOMContentLoaded', function () {
            // 获取页面元素
            const pasteArea = document.getElementById('pasteArea');       // 粘贴/拖放区域
            const imagePreview = document.getElementById('imagePreview'); // 图片预览容器
            const previewImg = document.getElementById('expandable-image');     // 预览图片元素
            //const clearBtn = document.getElementById('clearBtn');         // 清除按钮
            const recognizeText = document.getElementById('recognizeText'); // 识别文字按钮
            const handerOllama = document.getElementById('handerOllama'); // 大模型Ollama
            const downloadORCData = document.getElementById('downloadORCData'); // 下载数据

            // 监听粘贴事件
            document.addEventListener('paste', function (e) {
                // 检查剪贴板数据是否存在
                if (e.clipboardData && e.clipboardData.items) {
                    const items = e.clipboardData.items;
                    // 遍历剪贴板项目
                    for (let i = 0; i < items.length; i++) {
                        // 查找图片类型的数据
                        if (items[i].type.indexOf('image') !== -1) {
                            // 获取图片文件对象
                            const blob = items[i].getAsFile();
                            // 创建对象URL用于预览
                            const url = URL.createObjectURL(blob);

                            // 更新页面显示
                            previewImg.src = url;               // 设置预览图片源
                            imagePreview.style.display = 'block'; // 显示预览容器

                            // 可选：平滑滚动到预览区域（已注释）
                            // imagePreview.scrollIntoView({ behavior: 'smooth' });
                            uploadFile();
                            break; // 找到图片后停止查找
                        }
                    }
                }
            });

            // 拖放区域事件处理 - 拖动进入
            pasteArea.addEventListener('dragover', function (e) {
                e.preventDefault(); // 阻止默认行为以允许放置
                pasteArea.classList.add('dragover'); // 添加拖动样式
            });

            // 拖放区域事件处理 - 拖动离开
            pasteArea.addEventListener('dragleave', function () {
                pasteArea.classList.remove('dragover'); // 移除拖动样式
            });

            // 拖放区域事件处理 - 放置文件
            pasteArea.addEventListener('drop', function (e) {
                e.preventDefault(); // 阻止默认行为
                pasteArea.classList.remove('dragover'); // 移除拖动样式

                // 获取放置的文件
                const files = e.dataTransfer.files;
                if (files.length) {
                    const file = files[0]; // 获取第一个文件
                    // 检查是否为图片文件
                    if (file.type.indexOf('image') !== -1) {
                        // 创建对象URL用于预览
                        const url = URL.createObjectURL(file);

                        // 更新页面显示
                        previewImg.src = url;               // 设置预览图片源
                        imagePreview.style.display = 'block'; // 显示预览容器

                        // 可选：平滑滚动到预览区域（已注释）
                        // imagePreview.scrollIntoView({ behavior: 'smooth' });
                        uploadFile();
                    }
                }
            });

            // 清除按钮点击事件 - 重置预览
            /*clearBtn.addEventListener('click', function() {
                previewImg.src = '';                     // 清空图片源
                imagePreview.style.display = 'none';     // 隐藏预览容器
            });*/

            // 识别文字按钮点击事件 - 调用上传函数
            recognizeText.addEventListener('click', uploadFile);
            // 大模型识别 - 调用上传函数
            handerOllama.addEventListener('click', ollama);
            // 下载数据 - 调用上传函数
            downloadORCData.addEventListener('click', downloadJson);

            // 粘贴区域点击事件 - 提示用户如何粘贴
            /*pasteArea.addEventListener('click', function() {
                alert('请使用 Ctrl+V (Windows) 或 Cmd+V (Mac) 粘贴截图');
            });*/
        });

        // 异步上传文件函数
        async function uploadFile() {
            const resultDiv = document.getElementById('text-recognition'); // 获取结果展示区域
            resultDiv.innerHTML = "<-- PaddleOCR 启动 -->"
            const img = document.getElementById('expandable-image'); // 获取预览图片元素

            // 获取图片数据
            const response = await fetch(img.src);
            const blob = await response.blob(); // 转换为Blob对象

            // 创建表单数据
            const formData = new FormData();
            formData.append('file', blob); // 添加图片文件到表单数据

            try {
                // 发送POST请求到OCR API
                const response = await fetch('/api/ocr/', {
                    method: 'POST',
                    body: formData
                });

                // 解析响应数据
                const data = await response.json();
                showResults(data); // 显示识别结果
            } catch (error) {
                // 错误处理
                alert('识别失败: ' + error.message);
            }
        }
        let text_recognition = {};
        // 显示识别结果函数
        function showResults(data) {
            text_recognition = JSON.parse(JSON.stringify(data))
            const resultDiv = document.getElementById('text-recognition'); // 获取结果展示区域

            // 检查识别状态
            if (data.status !== 'success') {
                // 显示错误信息
                resultDiv.value = `错误: ${data.detail}`;
                return;
            }
            let html = '';
            data.results.forEach(item => {
                html += `<li><p>${item}</p></li>`;
            });
            // 显示成功结果（将数组转换为换行文本）
            resultDiv.innerHTML = html;
            ollama();
        }
        // 显示识别结果函数
        function ollama() {
            const text = text_recognition.results.join(" ");
            OAC.streamChat(text);
        }
        function copyToClipboard(text) {
            navigator.clipboard.writeText(text)
                .then(() => {
                    //console.log('内容已复制到剪贴板:', text);
                    alert('内容已复制到剪贴板:' + JSON.stringify(text))
                    // 可以在这里添加成功提示
                })
                .catch(err => {
                    //console.error('复制失败:', err);
                    alert('复制失败:' + JSON.stringify(err))
                    // 可以在这里添加错误提示
                });
        }
        document.getElementById('copyButton').addEventListener('click', () => {
            copyToClipboard(JSON.stringify(text_recognition));
        });

        function downloadJson() {
            var d = new Date();
            var n = d.toISOString().replaceAll(":", ".");
            let fileName = "ORCData." + n + ".json";
            let jsonString = JSON.stringify(ocrData, null, 2);
            let blob = new Blob([jsonString], { type: 'application/json' });
            let url = URL.createObjectURL(blob);
            let link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            console.log("成功下载文件：" + fileName);
        }
    </script>
</body>

</html>